﻿using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MishraReader.Entities;

#if !WINRT
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
#else
using Windows.Storage;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#endif


namespace MishraReader
{
    internal class OptionsManager : Notifier, IOptionsManager
    {
        public event EventHandler<EventArgs> ActivatedServicesChanged;
        public event EventHandler<EventArgs> OnRefreshTick;
        private readonly List<ShareServiceAccount> _activatedServices = new List<ShareServiceAccount>();
        private DispatcherTimer _dispatcher;
        private readonly ILightWeakEventManager _eventManager;
        private readonly IShareServicesProvider _servicesProvider;
        private int _refreshFrequency;
        private GridLength _leftColumnWidth;
        private GridLength _middleColumnWidth;
        private readonly static GridLengthConverter GridLengthConverter = new GridLengthConverter();

        private readonly TaskCompletionSource<bool> _loadCompleted = new TaskCompletionSource<bool>();

        public OptionsManager(IShareServicesProvider servicesProvider, ILightWeakEventManager eventManager)
        {
            _servicesProvider = servicesProvider;
            _eventManager = eventManager;

            OrderByPublicationDateDesc = true;
            MarkSelectedItemAsRead = true;

            RefreshFrequency = 60;
            MaxItemsByRequest = 50;

            AccentColorCode = "#FF6600";
            ShowOnlyPostSummary = true;
            ShowInTaskbar = IsRunningWindows7OrHigher; //if Windows 7, keep the application in taskbar by default
            UseNotificationIcon = !IsRunningWindows7OrHigher; //if Windows 7, hide the notification icon by default
            BrowserUseThemeColor = true;

            LeftColumnWidth = new GridLength(200);
            MiddleColumnWidth = new GridLength(340);



            LoadInternal().ContinueWith(_ =>
            {
                try
                {
                    _dispatcher = new DispatcherTimer
                    {
                        Interval = TimeSpan.FromSeconds(RefreshFrequency)
                    };
                    _dispatcher.Tick += dispatcher_Tick;

                    _dispatcher.Start();

                    // Save on close
                    _eventManager.Register(ApplicationMessages.ApplicationClosing, async () => await Persist());


                    _loadCompleted.SetResult(true);
                }
                catch (Exception e)
                {
                    
                    _loadCompleted.SetException(e);
                    throw;
                }
            }, TaskContinuationOptions.ExecuteSynchronously);

        }

        public string AccentColorCode { get; set; }

        /// <summary>
        ///   All activated services amoung those available
        /// </summary>
        public IEnumerable<ShareServiceAccount> ActivatedServices
        {
            get { return _activatedServices; }
        }

        public String Background { get; set; }
        public bool BrowserUseThemeColor { get; set; }
        public string Login { get; set; }
        public bool MarkSelectedItemAsRead { get; set; }
        public int MaxItemsByRequest { get; set; }

        public bool OrderByPublicationDateDesc { get; set; }
        public string Password { get; set; }

        public int RefreshFrequency
        {
            get { return _refreshFrequency; }
            set
            {
                _refreshFrequency = value;

                if (_dispatcher != null)
                    _dispatcher.Interval = TimeSpan.FromSeconds(_refreshFrequency);
            }
        }

        public bool ShowInTaskbar { get; set; }
        public bool ShowOnlyPostSummary { get; set; }
        public bool UseNotificationIcon { get; set; }
        public GridLength LeftColumnWidth
        {
            get { return _leftColumnWidth; }
            set
            {
                Set(ref _leftColumnWidth, value);
            }
        }

        public GridLength MiddleColumnWidth
        {
            get { return _middleColumnWidth; }
            set { Set(ref _middleColumnWidth, value); }
        }

        /// <summary>
        ///   Gets the service account associated to the defined service
        /// </summary>
        /// <param name="shareServicePackage"> </param>
        /// <returns> </returns>
        public ShareServiceAccount GetServiceAccount(IShareServicePackage shareServicePackage)
        {
            return ActivatedServices.FirstOrDefault(s => s.ServicePackage == shareServicePackage);
        }

        public Task Load()
        {
            return _loadCompleted.Task;
        }


        private async Task LoadInternal()
        {
#if !WINRT
            var file = ConfigFile;

            if (!File.Exists(file))
            {
                return;
            }
#else
            StorageFile sfile;
            var folder = ApplicationData.Current.RoamingFolder;
            try
            {
                sfile = await folder.GetFileAsync(ConfigFile);
            }
            catch(FileNotFoundException)
            {
                return; // nothing to do here
            }

            var file = await sfile.OpenStreamForReadAsync();
#endif

            try
            {
                using (var reader = new StreamReader(file))
                {
                    Login = reader.ReadLine();
                    Password = CryptoService.Decrypt(await reader.ReadLineAsync());

                    MaxItemsByRequest = int.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                        ShowInTaskbar = bool.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                        AccentColorCode = await reader.ReadLineAsync();

                    if (!reader.EndOfStream)
                        ShowOnlyPostSummary = bool.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                        BrowserUseThemeColor = bool.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                    {
                        var activatedServicesCount = int.Parse(await reader.ReadLineAsync());
                        for (var i = 0; i < activatedServicesCount; i++)
                        {
                            var serviceId = reader.ReadLine();
                            var userName = reader.ReadLine();
                            var password = CryptoService.Decrypt(await reader.ReadLineAsync());
                            var token = reader.ReadLine();
                            var isSelected = bool.Parse(await reader.ReadLineAsync());

                            var package =
                                _servicesProvider.AvailableServices.FirstOrDefault(
                                    s => s.ServiceId.ToString() == serviceId);

                            var account = new ShareServiceAccount(package)
                                              {
                                                  UserName = userName,
                                                  Password = password,
                                                  Token = token,
                                                  IsSelected = isSelected
                                              };

                            _activatedServices.Add(account);
                        }
                    }

                    if (!reader.EndOfStream)
                    {
                        UseNotificationIcon = bool.Parse(await reader.ReadLineAsync());
                        if (!UseNotificationIcon && !ShowInTaskbar)
                        {
                            ShowInTaskbar = true;
                        }
                    }

                    if (!reader.EndOfStream)
                        Background = await reader.ReadLineAsync();


                    MarkSelectedItemAsRead = true;

                    if (!reader.EndOfStream)
                        OrderByPublicationDateDesc = bool.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                        MarkSelectedItemAsRead = bool.Parse(await reader.ReadLineAsync());

                    if (!reader.EndOfStream)
                        LeftColumnWidth = (GridLength)GridLengthConverter.ConvertFromInvariantString(await reader.ReadLineAsync());
                    
                    if (!reader.EndOfStream)
                        MiddleColumnWidth = (GridLength)GridLengthConverter.ConvertFromInvariantString(await reader.ReadLineAsync());
                }
            }
            catch
            {
                Login = String.Empty;
                Password = String.Empty;
            }
        }

        public async Task Persist()
        {
#if !WINRT
            if (!Directory.Exists(ConfigFolder))
                Directory.CreateDirectory(ConfigFolder);
#endif


#if !WINRT
            using (var writer = new StreamWriter(ConfigFile))
#else
            var folder = ApplicationData.Current.RoamingFolder;
            var file = await folder.CreateFileAsync(ConfigFile, CreationCollisionOption.ReplaceExisting);
            
            using (var writer = new StreamWriter(await file.OpenStreamForWriteAsync()))
#endif
            {
                await writer.WriteLineAsync(Login ?? string.Empty);
                await writer.WriteLineAsync(CryptoService.Crypt(Password));
                writer.WriteLine(MaxItemsByRequest);
                writer.WriteLine(ShowInTaskbar);
                await writer.WriteLineAsync(AccentColorCode ?? string.Empty);
                writer.WriteLine(ShowOnlyPostSummary);
                writer.WriteLine(BrowserUseThemeColor);

                writer.WriteLine(ActivatedServices.Count());
                foreach (var service in ActivatedServices)
                {
                    await writer.WriteLineAsync(service.ServicePackage.ServiceId.ToString());
                    await writer.WriteLineAsync(service.UserName ?? string.Empty);
                    await writer.WriteLineAsync(CryptoService.Crypt(service.Password));
                    await writer.WriteLineAsync(service.Token ?? string.Empty);
                    writer.WriteLine(service.IsSelected);
                }

                writer.WriteLine(UseNotificationIcon);
                await writer.WriteLineAsync(Background ?? string.Empty);
                writer.WriteLine(OrderByPublicationDateDesc);
                writer.WriteLine(MarkSelectedItemAsRead);
                await writer.WriteLineAsync(GridLengthConverter.ConvertToInvariantString(LeftColumnWidth));
                await writer.WriteLineAsync(GridLengthConverter.ConvertToInvariantString(MiddleColumnWidth));
            }
        }

        public async void ReplaceActivatedServices(IEnumerable<ShareServiceAccount> services)
        {
            await Load();

            _activatedServices.Clear();
            _activatedServices.AddRange(services);

            var evt = ActivatedServicesChanged;
            if (evt != null)
                evt(this, EventArgs.Empty);
        }

        public async void UpdateAccentColor()
        {
            await Load();

            try
            {
                var newAccentColor = ColorExtensions.GetColorFromHexValue(AccentColorCode);
                Application.Current.Resources["MetroColorFeature"] = newAccentColor;
                Application.Current.Resources["MetroAccentBrush"] = new SolidColorBrush(newAccentColor);
                Application.Current.Resources["MetroProgressDark"] = new SolidColorBrush(newAccentColor);
            }
            catch (Exception)
            {
            }


            /*     Application.Current.Resources["SelectedForegroundColor"] = newAccentColor;


                 SolidColorBrush accentBrush = Application.Current.Resources["AccentBrush"] as SolidColorBrush;

                 ColorAnimation colorAnimation = new ColorAnimation(newAccentColor, new Duration(TimeSpan.FromMilliseconds(100)));
                 Storyboard.SetTarget(colorAnimation, accentBrush);
                 Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("Color"));

                 accentBrush.BeginAnimation(SolidColorBrush.ColorProperty, colorAnimation);*/
        }

        private void dispatcher_Tick(object sender, 
#if !WINRT
            EventArgs
#else
            object
#endif
            e)
        {
            if (OnRefreshTick != null)
                OnRefreshTick(this, EventArgs.Empty);
        }

        public static string ConfigFile {
#if !WINRT
            get { return Path.Combine(ConfigFolder, "mishrareader.config"); }
#else
            get { return "mishrareader.config"; }
#endif
        }

#if !WINRT
        public static string ConfigFolder
        {
            get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MishraReader"); }
        }
#endif

        private static bool IsRunningWindows7OrHigher
        {
            get
            {
#if !WINRT
                return Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1;
#else
                return true;
#endif
            }
        }
    }
}